package com.java.basis.thread.cas;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

/**
 * CAS 使用条件，线程最好不要超过cpu核心数
 * @author wangning
 * @create 2022-01-28 10:38
 */
public class TestAccount02 {
	public static void main(String[] args) {
		BigDecimalAccount01.demo(new DecimalAccountCAS(new BigDecimal("10000")));

	}
}

class DecimalAccountCAS implements BigDecimalAccount01 {
	private AtomicReference<BigDecimal> balance;

	public DecimalAccountCAS(BigDecimal balance) {
		this.balance = new AtomicReference<>(balance);
	}

	@Override
	public BigDecimal getBalance() {
		return balance.get();
	}

	@Override
	public void withdraw(BigDecimal amount) {
		while (true) {
			BigDecimal prev = balance.get();
			BigDecimal next = prev.subtract(amount);
			if (balance.compareAndSet(prev, next)) {
				break;
			}
		}
	}
}


interface BigDecimalAccount01 {
	//获取余额
	BigDecimal getBalance();

	//取款
	void withdraw(BigDecimal amount);

	/**
	 * 方法内启动1000个 线程，每个线程做-10元操作
	 * 如果初始余额为10000.那么正确的结果就是0
	 */
	static void demo(BigDecimalAccount01 account) {
		List<Thread> ts = new ArrayList<>();
		for (int i = 0; i < 1000; i++) {
			ts.add(new Thread(() -> {
				account.withdraw(BigDecimal.TEN);
			}));
		}
		long start = System.nanoTime();
		ts.forEach(Thread::start);
		ts.forEach(t -> {
			try {
				t.join();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		});
		long end = System.nanoTime();
		System.out.println(account.getBalance() + "元 cost: " + (end-start)/1000_000 + "ms");

	}
}
